package com.ruoyi.auth.controller;


import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.ruoyi.auth.config.WxMaConfiguration;
import com.ruoyi.auth.form.WxMiniAppLoginBody;
import com.ruoyi.common.core.constant.SystemRoleConstants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.WeChatUtil;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.RemoteUserService;
import com.tdd.wx.users.config.DefaultWxUserConfig;
import com.tdd.wx.users.entity.WxUser;
import com.tdd.wx.users.mongo.WxUserHandler;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author loby
 */
@RestController
@RequestMapping("/wxminiapp")
@Api(tags = "微信小程序")
@Slf4j
public class WxMiniAppLoginController{


    @Autowired
    WxUserHandler wxUserHandler;
    @Autowired
    private TokenService tokenService;
    @Autowired
    DefaultWxUserConfig defaultWxUserConfig;

    @Autowired
    RemoteUserService remoteUserService;

    @ApiOperation("登录")
    @PostMapping("/open/login")
    @ApiParam(name = "origin", value = "来源:0：未知，1：出袋小程序(默认)，2.广告投放小程序，3.运维APP，4.广告投放网站，5.管理中台，..,coordinate:123.2323,343.343(经度,纬度)")
    public R<?> login(@RequestBody WxMiniAppLoginBody form, @RequestParam(value = "origin", required = false) Integer origin){

        WxMaService wxService = WxMaConfiguration.getMaService(form.getAppid());
        try{
            WxMaJscode2SessionResult session = wxService.jsCode2SessionInfo(form.getCode());
            if(session == null || StringUtils.isEmpty(session.getSessionKey())){
                return R.fail("登录失败！");
            }
            log.info("当前登录用户uid：{}", session.getUnionid());
            WxUser wxUser = wxUserHandler.findByUnionId(session.getUnionid());
            if(wxUser == null){
                WxMaUserInfo wxMaUserInfo = wxService.getUserService().getUserInfo(session.getSessionKey(), form.getDatail(), form.getIv());
                wxUser = new WxUser();
                wxUser.setUnionId(session.getUnionid());
                //                wxUser.setOpenId(session.getOpenid());
                if(origin == null){
                    wxUser.setOrgin(1);
                    wxUser.setOpenId(session.getOpenid());
                }else {
                    wxUser.setOrgin(origin);
                    switch(origin){
                        case 1:
                            wxUser.setOpenId(session.getOpenid());
                            break;
                        case 2:
                            wxUser.setOpenIdAdv(session.getOpenid());
                            break;
                        case 3:
                            wxUser.setOpenIdMan(session.getOpenid());
                            break;
                        case 4:
                            wxUser.setOpenId4(session.getOpenid());
                            break;
                        default:
                            wxUser.setOpenId5(session.getOpenid());
                    }
                }
                if(form.getLongitude() != null){
                    wxUser.setLongitude(getDouble(form.getLongitude()));
                }
                if(form.getLatitude() != null){
                    wxUser.setLatitude(getDouble(form.getLatitude()));
                }
                wxUser.setAvatar(wxMaUserInfo.getAvatarUrl());
                wxUser.setNickName(wxMaUserInfo.getNickName());
                WxMaPhoneNumberInfo telInfo = wxService.getUserService().getPhoneNoInfo(session.getSessionKey(), form.getTelDatail(), form.getTelIv());
                wxUser.setPhone(telInfo.getPhoneNumber());
                wxUser.setGener(wxMaUserInfo.getGender());
                log.info("当前登录用户来源：{},用户名：{}", origin, wxUser.getNickName());
                wxUserHandler.insert(wxUser);
            }else {
                log.debug("wxService.getUserService().getUserInfo({},{},{})", session.getSessionKey(), form.getDatail(), form.getIv());
                WxMaUserInfo wxMaUserInfo = wxService.getUserService().getUserInfo(session.getSessionKey(), form.getDatail(), form.getIv());
                wxUser.setAvatar(wxMaUserInfo.getAvatarUrl());
                wxUser.setGener(wxMaUserInfo.getGender());
                if(origin == null){
                    origin = 1;
                }
                if(origin == 1 && wxUser.getOpenId() == null){
                    wxUser.setOpenId(session.getOpenid());
                }else if(origin == 2 && ObjectUtils.isEmpty(wxUser.getOpenIdAdv())){
                    wxUser.setOpenIdAdv(session.getOpenid());
                }else if(origin == 3 && ObjectUtils.isEmpty(wxUser.getOpenIdMan())){
                    wxUser.setOpenIdMan(session.getOpenid());
                }else if(origin == 4 && ObjectUtils.isEmpty(wxUser.getOpenId4())){
                    wxUser.setOpenId4(session.getOpenid());
                }else if(origin == 5 && ObjectUtils.isEmpty(wxUser.getOpenId5())){
                    wxUser.setOpenId5(session.getOpenid());
                }
                wxUserHandler.update(wxUser);
            }
            if(wxUser.getSysUserId() == null){
                wxUser = defaultWxUserConfig.getDefaultUser(wxUser);
            }
            return R.ok(tokenService.createWxToken(wxUser));
        }catch(Exception e){
            log.error("登录失败:" + e.getMessage(), e);
            return R.fail("登录失败！===>" + e.getMessage());
        }
    }

    Double getDouble(String str){
        Double ret = null;
        try{
            ret = Double.valueOf(str);
        }catch(Exception e){
            log.error("错误的坐标信息：{}", str);
        }
        return ret;
    }

    @ApiOperation("通过微信平台获取用户OpenId")
    @GetMapping("/getOpenId/{appid}/{code}")
    public R<?> getOpenId(@PathVariable("appid") String appid, @PathVariable("code") String code){
        if(StringUtils.isBlank(code)){
            return R.fail("empty jscode");
        }
        WxMaService wxService = WxMaConfiguration.getMaService(appid);
        try{
            WxMaJscode2SessionResult jscode2SessionResult = wxService.jsCode2SessionInfo(code);
            if(jscode2SessionResult == null || StringUtils.isEmpty(jscode2SessionResult.getSessionKey())){
                return R.fail("获取失败！");
            }
            return R.ok(jscode2SessionResult.getOpenid());
        }catch(Exception e){
            e.printStackTrace();
            log.debug("预登录失败：", e);
            return R.fail(e.getLocalizedMessage());
        }
    }

    /**
     * 为了避免已登录用户还需要点击授权，提前预登录
     * 如果用户已注册过，则直接登录
     *
     * @return
     */
    @ApiOperation("登录")
    @GetMapping({"/preLogin/{appid}/{code}/{origin}", "/preLogin/{appid}/{code}"})
    public R<?> checkLogin(@PathVariable("appid") String appid, @PathVariable("code") String code, @RequestParam(value = "origin", required = false) Integer origin){
        if(StringUtils.isBlank(code)){
            return R.fail("empty jscode");
        }
        WxMaService wxService = WxMaConfiguration.getMaService(appid);
        try{
            WxMaJscode2SessionResult session = wxService.jsCode2SessionInfo(code);
            if(session == null || StringUtils.isEmpty(session.getSessionKey())){
                return R.fail("登录失败！");
            }
            WxUser wxUser = wxUserHandler.findByUnionId(session.getUnionid());
            if(wxUser != null){
                //检查是否有对应的 OpenId
                boolean edited = false;
                if(origin == null){
                    origin = 1;
                }
                if(origin == 1 && wxUser.getOpenId() == null){
                    wxUser.setOpenId(session.getOpenid());
                    edited = true;
                }else if(origin == 2 && ObjectUtils.isEmpty(wxUser.getOpenIdAdv())){
                    wxUser.setOpenIdAdv(session.getOpenid());
                    edited = true;
                }else if(origin == 3 && ObjectUtils.isEmpty(wxUser.getOpenIdMan())){
                    wxUser.setOpenIdMan(session.getOpenid());
                    edited = true;
                }else if(origin == 4 && ObjectUtils.isEmpty(wxUser.getOpenId4())){
                    wxUser.setOpenId4(session.getOpenid());
                    edited = true;
                }else if(origin == 5 && ObjectUtils.isEmpty(wxUser.getOpenId5())){
                    wxUser.setOpenId5(session.getOpenid());
                    edited = true;
                }
                if(edited){
                    wxUserHandler.update(wxUser);
                }
                if(wxUser.getSysUserId() == null){
                    wxUser = defaultWxUserConfig.getDefaultUser(wxUser);
                }
                return R.ok(tokenService.createWxToken(wxUser));
            }else {
                log.debug("用户 getUnionid:{}未找到:{}", session.getUnionid(), session);
                return R.fail("用户 getUnionid:" + session.getUnionid() + "未找到");
            }
        }catch(WxErrorException e){
            e.printStackTrace();
            log.debug("预登录失败：", e);
            return R.fail(e.getLocalizedMessage());
        }
        //return R.fail();
    }


    /**
     * 为了避免已登录用户还需要点击授权，提前预登录
     * 如果用户已注册过，则直接登录
     *
     * @return
     */
    @ApiOperation("登录")
    @GetMapping({"/preLoginAdv/{appid}/{code}/{origin}", "/preLoginAdv/{appid}/{code}"})
    public R<?> checkLoginAdv(@PathVariable("appid") String appid, @PathVariable("code") String code, @RequestParam(value = "origin", required = false) Integer origin){
        if(StringUtils.isBlank(code)){
            return R.fail("empty jscode");
        }
        WxMaService wxService = WxMaConfiguration.getMaService(appid);
        try{
            WxMaJscode2SessionResult session = wxService.jsCode2SessionInfo(code);
            if(session == null || StringUtils.isEmpty(session.getSessionKey())){
                return R.fail("登录失败！");
            }
            WxUser wxUser = wxUserHandler.findByUnionId(session.getUnionid());
            if(wxUser != null){
                String params = SystemRoleConstants.MAINTAINER_ROLE_ID +"," + SystemRoleConstants.ADVERTISING_ROLE_ID +"," + SystemRoleConstants.ADV_MAINTAINER_ROLE_ID;
                String result = remoteUserService.checkIsAdvertising(wxUser.getSysUserId(),params);
                String[] data = result.split(",");
                if(org.springframework.util.ObjectUtils.isEmpty(result)){
                    log.info("调用[ruoyi-system]服务失败");
                }
                log.info("调用[ruoyi-system]服务返回的结果==={}",result);
                boolean isMaintainer = Objects.equals(data[0],"0");
                boolean isAdvMaintainer = Objects.equals(data[1],"0");
                boolean isAdv = Objects.equals(data[2],"0");
                log.info("该系统用户=={}拥有服务商角色=={}拥有广告主角色=={}拥有广告服务商角色=={}",wxUser.getSysUserId(),isMaintainer,isAdv,isAdvMaintainer);
                if(wxUser.getSysUserId() != null ){

                    //检查是否有对应的 OpenId
                    boolean edited = false;
                    if(origin == null){
                        origin = 1;
                    }
                    if(origin == 1 && wxUser.getOpenId() == null){
                        wxUser.setOpenId(session.getOpenid());
                        edited = true;
                    }else if(origin == 2 && ObjectUtils.isEmpty(wxUser.getOpenIdAdv())){
                        wxUser.setOpenIdAdv(session.getOpenid());
                        edited = true;
                    }else if(origin == 3 && ObjectUtils.isEmpty(wxUser.getOpenIdMan())){
                        wxUser.setOpenIdMan(session.getOpenid());
                        edited = true;
                    }else if(origin == 4 && ObjectUtils.isEmpty(wxUser.getOpenId4())){
                        wxUser.setOpenId4(session.getOpenid());
                        edited = true;
                    }else if(origin == 5 && ObjectUtils.isEmpty(wxUser.getOpenId5())){
                        wxUser.setOpenId5(session.getOpenid());
                        edited = true;
                    }
                    if(edited){
                        wxUserHandler.update(wxUser);
                    }
                    //                    if(wxUser.getSysUserId() == null){
                    //                        wxUser = defaultWxUserConfig.getDefaultUser(wxUser);
                    //                    }
                    return R.ok(tokenService.createWxTokenAdv(wxUser,isMaintainer,isAdv,isAdvMaintainer));
                }
                log.debug("用户没有systemID，或不是广告主用户");
            }
            log.debug("用户 getUnionid:{}未找到:{}", session.getUnionid(), session);
            return R.fail("用户 getUnionid:" + session.getUnionid() + "未找到");

        }catch(WxErrorException e){
            e.printStackTrace();
            log.debug("预登录失败：", e);
            return R.fail(e.getLocalizedMessage());
        }
        //return R.fail();
    }

    @ApiOperation("登录")
    //@GetMapping("/login/{appid}/{code}")
    public AjaxResult login(@PathVariable("appid") String appid, @PathVariable("code") String code, @RequestParam(value = "origin", required = false) Integer origin){
        if(StringUtils.isBlank(code)){
            return AjaxResult.error("empty jscode");
        }
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);
        try{
            WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
            if(session == null || StringUtils.isEmpty(session.getSessionKey())){
                return AjaxResult.error("登录失败！");
            }
            WxUser wxUser = wxUserHandler.findByUnionId(session.getUnionid());
            if(wxUser == null){
                wxUser = new WxUser();
                wxUser.setUnionId(session.getUnionid());
                //来源0：未知，1：出袋小程序，2.广告投放小程序，3.运维APP，4.广告投放网站，5.管理中台，..
                if(origin == null){
                    wxUser.setOrgin(1);
                    //未知的小程序
                    wxUser.setOpenId(session.getOpenid());
                }else {
                    wxUser.setOrgin(origin);
                    switch(origin){
                        case 1:
                            wxUser.setOpenId(session.getOpenid());
                            break;
                        case 2:
                            wxUser.setOpenIdAdv(session.getOpenid());
                            break;
                        case 3:
                            wxUser.setOpenIdMan(session.getOpenid());
                            break;
                        case 4:
                            wxUser.setOpenId4(session.getOpenid());
                            break;
                        default:
                            wxUser.setOpenId5(session.getOpenid());
                    }
                }
                wxUserHandler.insert(wxUser);
            }else {//检查 相应OpenId是否有值
                boolean edited = false;
                if(origin == 1 && wxUser.getOpenId() == null){
                    wxUser.setOpenId(session.getOpenid());
                    edited = true;
                }else if(origin == 2 && ObjectUtils.isEmpty(wxUser.getOpenIdAdv())){
                    wxUser.setOpenIdAdv(session.getOpenid());
                    edited = true;
                }else if(origin == 3 && ObjectUtils.isEmpty(wxUser.getOpenIdMan())){
                    wxUser.setOpenIdMan(session.getOpenid());
                    edited = true;
                }else if(origin == 4 && ObjectUtils.isEmpty(wxUser.getOpenId4())){
                    wxUser.setOpenId4(session.getOpenid());
                    edited = true;
                }else if(origin == 5 && ObjectUtils.isEmpty(wxUser.getOpenId5())){
                    wxUser.setOpenId5(session.getOpenid());
                    edited = true;
                }
                if(edited){
                    wxUserHandler.update(wxUser);
                }
            }

            tokenService.createWxToken(wxUser);//,session.getSessionKey());
            return AjaxResult.success("登录成功", session);
        }catch(Exception e){
            e.printStackTrace();
            return AjaxResult.error("登录失败！===>" + e.getMessage());
        }
    }

    @ApiOperation("获取用户信息")
    @GetMapping("/getInfo/{appid}/{sessionKey}/{signature}/{rawData}/{encryptedData}/{iv}")
    public AjaxResult getInfo(@PathVariable("appid") String appid, @PathVariable("sessionKey") String sessionKey, @PathVariable("signature") String signature, @PathVariable("rawData") String rawData, @PathVariable("encryptedData") String encryptedData, @PathVariable("iv") String iv){
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);

        try{
            // 用户信息校验
            if(! wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)){
                return AjaxResult.error("user check failed");
            }
            // 解密用户信息
            WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(sessionKey, encryptedData, iv);
            if(userInfo != null){
                WxUser wxUser = wxUserHandler.findByUnionId(userInfo.getUnionId());
                if(wxUser == null){
                    wxUser = new WxUser();
                }
                wxUser.setUnionId(userInfo.getUnionId());
                wxUser.setOpenId(userInfo.getOpenId());
                wxUser.setAvatar(userInfo.getAvatarUrl());
                wxUser.setGener(userInfo.getGender());
                wxUser.setNickName(userInfo.getNickName());
                wxUser.setCity(userInfo.getCity());
                wxUser.setCountry(userInfo.getCountry());
                wxUser.setProvince(userInfo.getProvince());
                wxUserHandler.update(wxUser);

                return AjaxResult.success("获取用户信息成功", userInfo);
            }
        }catch(Exception e){
            log.error("获取用户信息失败" + e.getLocalizedMessage(), e);
            return AjaxResult.error("获取用户信息失败" + e.getLocalizedMessage());
        }
        return AjaxResult.error("获取用户信息失败");
    }

    @ApiOperation("获取手机信息")
    @GetMapping("/getPhone/{appid}/{sessionKey}/{signature}/{rawData}/{encryptedData}/{iv}")
    public AjaxResult getPhone(@PathVariable("appid") String appid, @PathVariable("sessionKey") String sessionKey, @PathVariable("signature") String signature, @PathVariable("rawData") String rawData, @PathVariable("encryptedData") String encryptedData, @PathVariable("iv") String iv){
        final WxMaService wxService = WxMaConfiguration.getMaService(appid);

        try{
            // 用户信息校验
            if(! wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)){
                return AjaxResult.error("user check failed");
            }
            // 解密用户信息
            WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
            if(phoneNoInfo != null){
                String unionId = SecurityUtils.getUnionId();//.getOpenId();
                WxUser wxUser = wxUserHandler.findByUnionId(unionId);
                if(wxUser == null){
                    wxUser = new WxUser();
                }
                wxUser.setPhone(phoneNoInfo.getPurePhoneNumber());
                wxUserHandler.update(wxUser);
                return AjaxResult.success("获取用户手机信息成功", phoneNoInfo);
            }
        }catch(Exception e){
            log.error("获取用户手机信息失败" + e.getLocalizedMessage(), e);
            return AjaxResult.error("获取用户手机信息失败" + e.getLocalizedMessage());
        }
        return AjaxResult.error("获取用户手机信息失败");
    }

    @ApiOperation("生成广告机二维码")
    @GetMapping("/open/createQrCode")
    public R createQrCode(String scene){
        WxMaService wxService = WxMaConfiguration.getMaService("wx4042c90418a900f1");
        try{
            String code = WeChatUtil.createQrCode(wxService.getAccessToken(), scene);
            return R.ok(code);
        }catch(Exception e){
            e.printStackTrace();
            return R.fail(e.getMessage());
        }
    }

}
